package com.quanyan.stadium.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.quanyan.api.APIResponse;
import com.quanyan.common.Plugin.Page;
import com.quanyan.common.Plugin.PageObj;
import com.quanyan.common.constants.Constants;
import com.quanyan.common.utils.GsonUtils;
import com.quanyan.common.utils.ServletUtils;
import com.quanyan.common.utils.StringUtil;
import com.quanyan.common.utils.TimeUtils;
import com.quanyan.place.client.PlaceClient;
import com.quanyan.stadium.api.req.*;
import com.quanyan.stadium.api.resp.*;
import com.quanyan.stadium.biz.BizDatesportJoinInfoDao;
import com.quanyan.stadium.constants.DatesportConstants;
import com.quanyan.stadium.entity.*;
import com.quanyan.stadium.entity.vo.*;
import com.quanyan.stadium.mapper.DatesportMapper;
import com.quanyan.stadium.mapper.TbDatesportInfoMapper;
import com.quanyan.stadium.mapper.TbDatesportNoticeInfoMapper;
import com.quanyan.stadium.service.*;
import com.quanyan.stadium.service.commonComponent.*;
import com.quanyan.stadium.utils.DatesportHelper;
import com.quanyan.user.response.RespOpenUserInterest;
import com.quanyan.user.response.RespUserInfoBase;
import com.quanyan.user.serviceFacade.UserServiceFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Created by Zheng.Ke
 * Date 2016/7/7.
 */
@Service("datesportService")
public class DatesportServiceImpl implements DatesportService {
    private static Logger logger = LoggerFactory.getLogger(DatesportServiceImpl.class);

    @Autowired
    private TbDatesportInfoMapper tbDatesportInfoMapper;
    @Autowired
    private TbDatesportNoticeInfoMapper tbDatesportNoticeInfoMapper;
    @Autowired
    private IMService iMService;
    @Autowired
    private MessagePushService messagePushService;
    @Autowired
    private UserServiceFacade userServiceFacade;
    @Autowired
    private BizDatesportJoinInfoDao bizDatesportJoinInfoDao;
    @Autowired
    private BaseService baseService;
    @Autowired
    private DatesportMqService datesportMqService;
    @Autowired
    private DatesportMapper datesportMapper;
    @Autowired
    private NearbyService nearbyService;
    @Autowired
    private PlaceClient placeClient;

    @Override
    public APIResponse<TbDatesportNoticeInfo> createDatesportNotice(ReqDatesportNotice reqDatesportNotice, int uid) {
        Integer datesportId = reqDatesportNotice.getDatesportId();
        String notice = reqDatesportNotice.getNotice();

        TbDatesportInfo tbDatesportInfo = tbDatesportInfoMapper.selectByPrimaryKey(datesportId);
        if (tbDatesportInfo == null) {
            return APIResponse.returnFail("datesportId不存在");
        }
        if (uid != tbDatesportInfo.getUid()) {
            return APIResponse.returnFail("只有约运动创建者才能发布公告。");
        }
        List<TbDatesportNoticeInfo> list = this.findNoticeInfoByDatesportId(datesportId, false);
        if (list.size() >= 10) {
            return  APIResponse.returnFail(110, "已超过公告上限10个。");
        }

        TbDatesportNoticeInfo tbDatesportNoticeInfo = new TbDatesportNoticeInfo();
        tbDatesportNoticeInfo.setCreateTime(new Date());
        tbDatesportNoticeInfo.setDatesportId(datesportId);
        tbDatesportNoticeInfo.setIsDelete(Constants.IS_DELETE_FALSE);
        tbDatesportNoticeInfo.setNotice(notice);
        tbDatesportNoticeInfoMapper.insertSelective(tbDatesportNoticeInfo);

        // 发送通知到活动参与者
        List<TbDatesportJoinInfo> joinInfoList = bizDatesportJoinInfoDao.findJoinedByDatesportId(datesportId);
        String title = tbDatesportInfo.getTitle();
        List<Integer> uidList = new ArrayList<Integer>();
        for (TbDatesportJoinInfo joinInfo : joinInfoList) {
            if (joinInfo.getStatus() == 6) {//创建者不需要
                continue;
            }
            uidList.add(joinInfo.getUid());
        }

        String creatorUrl = DatesportHelper.getCreatorHeadUrlByMebersInfoStr(tbDatesportInfo.getMembersInfo());
        messagePushService.pushNoticeMessage(title, uidList, datesportId, creatorUrl);

        return APIResponse.returnSuccess(tbDatesportNoticeInfo);
    }

    @Override
    public List<TbDatesportNoticeInfo> findNoticeInfoByDatesportId(int datesportId, boolean isDelete) {
        TbDatesportNoticeInfoExample example = new TbDatesportNoticeInfoExample();
        TbDatesportNoticeInfoExample.Criteria criteria = example.createCriteria();
        criteria.andDatesportIdEqualTo(datesportId);
        if (isDelete) {
            criteria.andIsDeleteEqualTo(Constants.IS_DELETE_TRUE);
        } else {
            criteria.andIsDeleteEqualTo(Constants.IS_DELETE_FALSE);
        }
        return tbDatesportNoticeInfoMapper.selectByExample(example);
    }

    @Override
    public APIResponse<?> createDatesportLabel(ReqDatesportLabelInfo reqDatesportLabelInfo) {
        TbDatesportInfo tbDatesportInfo = new TbDatesportInfo();

        tbDatesportInfo.setUid(reqDatesportLabelInfo.getUid());
        tbDatesportInfo.setPlayType(reqDatesportLabelInfo.getPlayType());
        tbDatesportInfo.setSportType(reqDatesportLabelInfo.getSportType());
        tbDatesportInfo.setPayType(reqDatesportLabelInfo.getPayType());
        tbDatesportInfo.setPlayerTrait(reqDatesportLabelInfo.getPlayerTrait());
        tbDatesportInfo.setPlayerLevel(reqDatesportLabelInfo.getPlayerLevel());
        tbDatesportInfo.setCostType(reqDatesportLabelInfo.getCostType());
        tbDatesportInfo.setGenderType(reqDatesportLabelInfo.getGenderType());
        tbDatesportInfo.setTimeFrame(reqDatesportLabelInfo.getTimeFrame());
        tbDatesportInfo.setDistanceRange(reqDatesportLabelInfo.getDistanceRange());
        tbDatesportInfo.setLat(reqDatesportLabelInfo.getLat());
        tbDatesportInfo.setLng(reqDatesportLabelInfo.getLng());
        tbDatesportInfo.setCreateTime(new Date());
        tbDatesportInfo.setUpdateTime(new Date());
        tbDatesportInfo.setCityId(reqDatesportLabelInfo.getCityId());

        tbDatesportInfoMapper.insertSelective(tbDatesportInfo);

        // 发送MQ
        Byte createType = reqDatesportLabelInfo.getCreateType();
        if (createType == 2) {
            datesportMqService.sendIToSports(reqDatesportLabelInfo.getUid());
        }

        RespDatesportLabel respDatesportLabel = new RespDatesportLabel();
        respDatesportLabel.setDatesportId(tbDatesportInfo.getId());
        return APIResponse.returnSuccess(respDatesportLabel);
    }

    @Override
    public APIResponse<?> createDatesportSet(ReqDatesportSetInfo reqDatesportSetInfo) {
        final Integer datesportId = reqDatesportSetInfo.getDatesportId();
        TbDatesportInfo tbDatesportInfo = tbDatesportInfoMapper.selectByPrimaryKey(datesportId);
        if (tbDatesportInfo == null) {
            return APIResponse.returnFail("datesportId不存在");
        }
        if (StringUtil.isNotBlank(tbDatesportInfo.getGroupId())) {
            return APIResponse.returnFail("你已经发布过该活动了，不能重复发布。");
        }

        final String title = reqDatesportSetInfo.getTitle();
        Integer playerCount = reqDatesportSetInfo.getPlayerCount();
        Byte isCheck = reqDatesportSetInfo.getIsCheck();
        final Integer uid = tbDatesportInfo.getUid();

        APIResponse<RespUserInfoBase> userInfo = userServiceFacade.queryUserInfo(uid);
        String headUrl = "";
        if (userInfo != null && userInfo.isRet()) {
            headUrl = userInfo.getData().getIcon();
        }
        CreateIMGroupVo requestVo = new CreateIMGroupVo();
        requestVo.setHead(headUrl);
        requestVo.setGroupname(title);
        requestVo.setGroupdescriptions(title);
        requestVo.setIspublic(0);
        requestVo.setMaxusers(playerCount);
        if (isCheck == DatesportConstants.NEED_CHECK) { //需要审核
            requestVo.setApproval(0);
        } else { // 不需要
            requestVo.setApproval(1);
        }
        requestVo.setOwner(uid+"");
        requestVo.setCurrentUid(uid);
        requestVo.setType(4);
        IMResponseGroupVo responseGroupVo = iMService.createIMGroup(requestVo);
        if (responseGroupVo.getErrcode() != 200) {
            return APIResponse.returnFail("调用C++端创建群组接口出错信息如下：" + responseGroupVo.getErrmsg());
        }
        JSONObject groupInfo = responseGroupVo.getData().getJSONArray("groupinfo").getJSONObject(0);
        String groupId = groupInfo.getString("groupid");
        String orderNo = reqDatesportSetInfo.getOrderNo();
        if (StringUtil.isNotBlank(orderNo)) {
            APIResponse response =  placeClient.isOrderUse(uid, orderNo, 1);// 通知订场使用了订单号
            if (response.getErrcode() != 200) {
                logger.error("通知订场使用了订单号失败，原因：{}，订单号：{}。", GsonUtils.toJson(response), orderNo);
                return APIResponse.returnFail("通知订场使用了订单号失败。");
            } else {
                logger.info("通知订场使用了订单号成功，晌应：{}，订单号：{}。", GsonUtils.toJson(response), orderNo);
            }
        }
        RespUserInfoBase joinUserInfo = baseService.queryUserMsg(uid);
        if (joinUserInfo == null) {
            logger.error("未找到用户相关信息。datesportId:{}", datesportId);
            return APIResponse.returnFail("未找到用户相关信息。");
        }

        final String jonnerIcon = joinUserInfo.getIcon();
        MemberInfo memberInfo = new MemberInfo();
        memberInfo.setUid(uid);
        memberInfo.setIcon(jonnerIcon);
        memberInfo.setNickName(joinUserInfo.getNickName());
        tbDatesportInfo.setJoinedCount(1);
        tbDatesportInfo.setMembersInfo(DatesportHelper.addMemberInfo(null, memberInfo));

        tbDatesportInfo.setUpdateTime(new Date());
        tbDatesportInfo.setGroupId(groupId);
        tbDatesportInfo.setTitle(title);
        if (joinUserInfo.getGender() != null) {
            tbDatesportInfo.setGenderStructure((byte) joinUserInfo.getGender().intValue());
        } else {
            tbDatesportInfo.setGenderStructure((byte) 0);// 男女一样多
        }
        tbDatesportInfo.setStartTime(reqDatesportSetInfo.getStartTime());
        tbDatesportInfo.setAddress(reqDatesportSetInfo.getAddress());
        tbDatesportInfo.setPlayerCount(playerCount);
        tbDatesportInfo.setPayType(reqDatesportSetInfo.getPayType());
        tbDatesportInfo.setIsCheck(isCheck);
        tbDatesportInfo.setPhone(reqDatesportSetInfo.getPhone());
        tbDatesportInfo.setIsPublicPhone(reqDatesportSetInfo.getIsPublicPhone());
        tbDatesportInfo.setIsBookingGym(reqDatesportSetInfo.getIsBookingGym());
        tbDatesportInfo.setOrderNo(orderNo);
        tbDatesportInfo.setInviteCount(DatesportConstants.MAX_INVITE_CNT);
        tbDatesportInfo.setInviteUpdateTime(new Date());
        tbDatesportInfo.setStatus(DatesportConstants.DATESPORT_STATUS_NO_CANCEL);

        tbDatesportInfoMapper.updateByPrimaryKeySelective(tbDatesportInfo);

        // 保存到活动参数表中
        TbDatesportJoinInfo tbDatesportJoinInfo = new TbDatesportJoinInfo();
        tbDatesportJoinInfo.setStatus((byte) 6);//创建者
        tbDatesportJoinInfo.setUpdateTime(new Date());
        tbDatesportJoinInfo.setCreateTime(new Date());
        tbDatesportJoinInfo.setDatesportId(datesportId);
        tbDatesportJoinInfo.setUid(uid);
        if (joinUserInfo.getGender() != null) {
            tbDatesportJoinInfo.setGender((byte) joinUserInfo.getGender().intValue());
        }
        bizDatesportJoinInfoDao.saveOrUpdateDatesportJoinInfo(tbDatesportJoinInfo);


       new Thread(new Runnable() {
           @Override
           public void run() {
               // 发送推送消息
               messagePushService.pushCreateDatesportSucessMsg(title, uid, datesportId, jonnerIcon);
               // 发送MQ
               datesportMqService.sendSportsWithMe(uid);
           }
       }).start();

        RespCreateDatesportSet resp = new RespCreateDatesportSet();
        resp.setGroupId(groupId);
        return APIResponse.returnSuccess(resp);
    }

    @Override
    public APIResponse<RespDatesportDetail> datesportDetail(ReqDatesportDetail reqDatesportDetail) {
        Integer uid = (Integer) ServletUtils.getHttpServletRequest().getAttribute("uid");
        TbDatesportInfo tbDatesportInfo = tbDatesportInfoMapper.selectByPrimaryKey(reqDatesportDetail.getDatesportId());
        if (tbDatesportInfo == null) {
            return APIResponse.returnFail("datesportId不存在");
        }
        Integer datesportId = reqDatesportDetail.getDatesportId();

        RespDatesportDetail detail = new RespDatesportDetail();
        detail.setUid(uid);
        detail.setCreatorUid(tbDatesportInfo.getUid());
        detail.setGroupId(tbDatesportInfo.getGroupId());
        detail.setDatesportId(datesportId);
        detail.setPayType(tbDatesportInfo.getPayType());
        detail.setTitle(tbDatesportInfo.getTitle());
        detail.setOrderNo(tbDatesportInfo.getOrderNo());
        detail.setAddress(tbDatesportInfo.getAddress());
        detail.setStartTime(tbDatesportInfo.getStartTime());
        detail.setIsBookingGym(tbDatesportInfo.getIsBookingGym());
        detail.setPlayerCount(tbDatesportInfo.getPlayerCount());
        detail.setIsCheck(tbDatesportInfo.getIsCheck());
        detail.setTagList(DatesportHelper.getTagListByTbDatesportInfo(tbDatesportInfo));
        detail.setMembersCount(tbDatesportInfo.getJoinedCount());
        detail.setDatesportStatus(tbDatesportInfo.getStatus());
        if (tbDatesportInfo.getIsPublicPhone() == 1) {//公开
            detail.setPhone(tbDatesportInfo.getPhone());
        } else if (tbDatesportInfo.getIsPublicPhone() == 2) { // 不公开
            detail.setPhone("");
        }

        // 成员图象
        List<MemberInfo> memberInfoList = DatesportHelper.getMemberListByMebersInfoStr(tbDatesportInfo.getMembersInfo());
        List<String> members = new ArrayList<>();
        for (int i=0; i<memberInfoList.size(); i++) {
            MemberInfo memberInfo = memberInfoList.get(i);
            members.add(memberInfo.getIcon());
        }
        detail.setMembers(members);

        TbDatesportJoinInfo tbDatesportJoinInfo = null;
        if (uid != null) {
            tbDatesportJoinInfo = bizDatesportJoinInfoDao.getByDatesportIdAndUid(datesportId, uid);;
        }
        Byte joinStatus = (byte)0;
        if (tbDatesportJoinInfo != null) {
            joinStatus = tbDatesportJoinInfo.getStatus();
        }
        detail.setJoinStatus(joinStatus);

        List<TbDatesportNoticeInfo> noticeInfoList = findNoticeInfoByDatesportId(datesportId, false);
        detail.setNoticeInfoList(transToRespNoticeInfo(noticeInfoList));// 转换下值
        return APIResponse.returnSuccess(detail);
    }

    @Override
    public APIResponse<RespRecommendInfo> recommendInfo(ReqRecommendInfo reqRecommendInfo) {
        TbDatesportInfo tbDatesportInfo = tbDatesportInfoMapper.selectByPrimaryKey(reqRecommendInfo.getDatesportId());
        if (tbDatesportInfo == null) {
            return APIResponse.returnFail("datesportId不存在");
        }
        Double lat = reqRecommendInfo.getLat();
        Double lng = reqRecommendInfo.getLng();
        Integer pageNum = reqRecommendInfo.getPageNum();
        Integer pageSize = reqRecommendInfo.getPageSize();

        RespRecommendInfo respRecommendInfo = new RespRecommendInfo();
        respRecommendInfo.setInviteCount(DatesportConstants.MAX_INVITE_CNT);
        respRecommendInfo.setInviteLeftCount(tbDatesportInfo.getInviteCount());

        List<RespMatchPeople> matchPeopleList = null;
        ValueHolder holder = new ValueHolder();
        if (lat == null || lng == null) {
            matchPeopleList = new ArrayList<RespMatchPeople>();
            holder.setValue(0);
        } else {
            matchPeopleList = getMatchPeople(tbDatesportInfo, pageNum, pageSize, lat, lng, holder);
        }

        respRecommendInfo.setRecommentPlayerCount((Integer) holder.getValue());
        respRecommendInfo.setMatchPeopleList(matchPeopleList);
        return APIResponse.returnSuccess(respRecommendInfo);
    }

    private List<RespMatchPeople> getMatchPeople(TbDatesportInfo tbDatesportInfo, Integer pageNum, Integer pageSize, Double lat, Double lng, ValueHolder holder) {
        List<RespMatchPeople> matchPeopleList = new ArrayList<RespMatchPeople>();

        List<TbDatesportInfo> tbDatesportInfos = datesportMapper.matchTagDatesport(tbDatesportInfo, 0, 500);
        logger.info("约运动：获取标签匹配的人数为：{}个。tbDatesportInfo:{}。", tbDatesportInfos.size(), GsonUtils.toJson(tbDatesportInfo));
        List<NearbyVo> nearbyVos = nearbyService.findByPosition(lat, lng, 0, 500, 5000);
        if (nearbyVos == null) {
            return matchPeopleList;
        }

        logger.info("约运动：获取附近的人数为：{}个。lat:{}, lng:{}。", nearbyVos.size(), lat, lng);

        // 转换为map，方便计算与取值
        Map<Integer, TbDatesportInfo> tbDatesportInfoMap = transInfoListToMap(tbDatesportInfos);// key -uid  value-TbDatesportInfo
        Map<Integer, NearbyVo> nearbyMap = transNearbyVosListToMap(nearbyVos);// key -uid value-NearbyVo

        // 两个map，根据uid做交集
        tbDatesportInfoMap.keySet().retainAll(nearbyMap.keySet());

        Integer creatorUid = tbDatesportInfo.getUid();

        List<Integer> commonUids = new ArrayList<Integer>();
        commonUids.addAll(tbDatesportInfoMap.keySet());
        for (NearbyVo nearbyVo : nearbyVos) {
            if (!commonUids.contains(nearbyVo.getUid()) && creatorUid != nearbyVo.getUid()) {
                commonUids.add(nearbyVo.getUid());
            }
        }
        // 移除自己
        commonUids.remove(creatorUid);

        holder.setValue(commonUids.size());

        // 分页
        int begin = pageNum*pageSize;
        if (commonUids.size() >= begin) {
            int fromIndex = begin;
            int toIndex = begin + pageSize;
            if (commonUids.size() <= toIndex) {
                toIndex = commonUids.size();
            }
            commonUids = commonUids.subList(fromIndex, toIndex);
        } else {
            commonUids.clear();
        }

        Map<Integer,RespUserInfoBase> map = userServiceFacade.batchQueryUserInfoToMap(commonUids);

        //为了获取用户参与此约运动的状态
        List<TbDatesportJoinInfo> joinInfoList = bizDatesportJoinInfoDao.findByDatesportIdAndUid(tbDatesportInfo.getId(), commonUids);
        Map<Integer, Byte> joinInfoMap = transJoinInfoListToMap(joinInfoList);// key--uid, value --status

        if (map != null) {
            for(Integer uid : commonUids) {
                RespMatchPeople respMatchPeople = new RespMatchPeople();
                RespUserInfoBase respUserInfoBase = map.get(uid);
                if (respUserInfoBase == null) {
                    continue;
                }
                if (joinInfoMap.containsKey(uid)) {
                    respMatchPeople.setJoinStatus(joinInfoMap.get(uid));
                } else {
                    respMatchPeople.setJoinStatus((byte) 0);
                }
                NearbyVo nearbyVo = nearbyMap.get(uid);
                Integer distance = null;
                if (nearbyVo != null) {
                    distance = nearbyVo.getDistance();
                }
                List<String> tagList = DatesportHelper.getTagListByTbDatesportInfo(tbDatesportInfoMap.get(uid));

                respMatchPeople.setUid(uid);
                respMatchPeople.setGender(respUserInfoBase.getGender());
                respMatchPeople.setHead(respUserInfoBase.getIcon());
                respMatchPeople.setNickName(respUserInfoBase.getNickName());
                respMatchPeople.setDistance(distance);
                respMatchPeople.setTagList(tagList);

                matchPeopleList.add(respMatchPeople);
            }
        }

        return matchPeopleList;
    }

    private Map<Integer, Byte> transJoinInfoListToMap(List<TbDatesportJoinInfo> joinInfoList) {
        Map<Integer, Byte> map = new HashMap<Integer, Byte>();
        for (TbDatesportJoinInfo joinInfo : joinInfoList) {
            map.put(joinInfo.getUid(), joinInfo.getStatus());
        }
        return map;
    }

    private Map<Integer, NearbyVo> transNearbyVosListToMap(List<NearbyVo> nearbyVos) {
        Map<Integer, NearbyVo> map = new HashMap<Integer, NearbyVo>();
        for (NearbyVo vo : nearbyVos) {
            map.put(vo.getUid(), vo);
        }
        return map;
    }

    private Map<Integer, TbDatesportInfo> transInfoListToMap(List<TbDatesportInfo> tbDatesportInfos) {
        Map<Integer, TbDatesportInfo> map = new HashMap<Integer, TbDatesportInfo>();
        for (TbDatesportInfo info : tbDatesportInfos) {
            map.put(info.getUid(), info);
        }
        return map;
    }

    @Override
    public APIResponse<RespInvitePeople> invitePeople(int datesportId, int invitedUid, int uid) {
        TbDatesportInfo tbDatesportInfo = tbDatesportInfoMapper.selectByPrimaryKey(datesportId);
        if (tbDatesportInfo == null) {
            return APIResponse.returnFail("datesportId不存在");
        }
        /*if (tbDatesportInfo.getUid() != uid) {
            return APIResponse.returnFail(ApiResponseEnum.ILLEGAL_PROTOCOL, "只有活动创建者才能邀请人");
        }*/
        int inviteCount = tbDatesportInfo.getInviteCount();
        if (inviteCount <= 0) {
            return APIResponse.returnFail(606, "今天的邀请次数已经用完了。");
        }

        // 更新次数
        tbDatesportInfo.setInviteCount(inviteCount-1);
        tbDatesportInfo.setInviteUpdateTime(new Date());
        tbDatesportInfoMapper.updateByPrimaryKeySelective(tbDatesportInfo);

        String nickname = "";
        APIResponse<RespUserInfoBase> ret = userServiceFacade.queryUserInfo(uid);
        if (ret != null && ret.isRet()) {
            nickname = ret.getData().getNickName();
        }
        String iconUrl = DatesportHelper.getCreatorHeadUrlByMebersInfoStr(tbDatesportInfo.getMembersInfo());
        boolean isSucessful = messagePushService.pushReceiveInviteMessage(tbDatesportInfo.getTitle(), invitedUid, nickname, datesportId, iconUrl);
        if (!isSucessful) {
            // 恢复次数
            tbDatesportInfo.setInviteCount(inviteCount);
            tbDatesportInfoMapper.updateByPrimaryKeySelective(tbDatesportInfo);
            return APIResponse.returnFail("发送邀请失败。");
        }

        // 保存到参加表中
        TbDatesportJoinInfo tbDatesportJoinInfo = new TbDatesportJoinInfo();
        tbDatesportJoinInfo.setDatesportId(datesportId);
        tbDatesportJoinInfo.setUid(invitedUid);
        tbDatesportJoinInfo.setCreateTime(new Date());
        tbDatesportJoinInfo.setUpdateTime(new Date());
        tbDatesportJoinInfo.setStatus((byte) 2);//被邀请
        bizDatesportJoinInfoDao.saveOrUpdateDatesportJoinInfo(tbDatesportJoinInfo);

        RespInvitePeople resp = new RespInvitePeople();
        resp.setInviteCount(DatesportConstants.MAX_INVITE_CNT);
        resp.setInviteLeftCount(tbDatesportInfo.getInviteCount());
        return APIResponse.returnSuccess(resp);
    }

    @Override
    @Transactional
    public APIResponse<?> updateUserDatesportStatus(ReqUpdateUserDatesportStatus reqUpdateUserDatesportStatus) {
        Integer datesportId = reqUpdateUserDatesportStatus.getDatesportId();
        Byte status = reqUpdateUserDatesportStatus.getStatus();
        Integer joinnerUid = reqUpdateUserDatesportStatus.getTargetId();

        TbDatesportInfo tbDatesportInfo = tbDatesportInfoMapper.selectByPrimaryKey(datesportId);
        if (tbDatesportInfo == null || StringUtil.isBlankOrNull(tbDatesportInfo.getGroupId())) {
            return APIResponse.returnFail("datesportId不存在或groupId为空");
        }
        TbDatesportJoinInfo tbDatesportJoinInfo = bizDatesportJoinInfoDao.getByDatesportIdAndUid(datesportId, joinnerUid);
        if (tbDatesportJoinInfo == null) {
            tbDatesportJoinInfo = new TbDatesportJoinInfo();
            tbDatesportJoinInfo.setDatesportId(datesportId);
            tbDatesportJoinInfo.setUid(joinnerUid);
            tbDatesportJoinInfo.setCreateTime(new Date());
            tbDatesportJoinInfo.setUpdateTime(new Date());
        }
        Byte originalStatus = tbDatesportJoinInfo.getStatus();
        tbDatesportJoinInfo.setStatus(status);

        String title = tbDatesportInfo.getTitle();
        Integer maxCnt = tbDatesportInfo.getPlayerCount();
        String groupId = tbDatesportInfo.getGroupId();
        String creatorUrl = DatesportHelper.getCreatorHeadUrlByMebersInfoStr(tbDatesportInfo.getMembersInfo());
        String membersInfo = tbDatesportInfo.getMembersInfo();
        Byte isCheck = tbDatesportInfo.getIsCheck();
        Integer creatorUid = tbDatesportInfo.getUid();
        RespUserInfoBase joinUserInfo = baseService.queryUserMsg(joinnerUid);
        if (joinUserInfo.getGender() != null) {
            tbDatesportJoinInfo.setGender((byte) joinUserInfo.getGender().intValue());
        }
        String joinnerNickName = joinUserInfo.getNickName();
        String joinnerIcon = joinUserInfo.getIcon();
        Byte datesportStatus = tbDatesportInfo.getStatus();
        int joinedCount = tbDatesportInfo.getJoinedCount();

        switch (status) {
            case 0: // 初始状态(游客)
                return APIResponse.returnFail("无效状态。");
            case 1: // 申请
                if (originalStatus != null && (originalStatus == 3 || originalStatus == 7)) {
                    return APIResponse.returnSuccess("你已加入，无需再申请。");
                }
                if (datesportStatus != null && datesportStatus == DatesportConstants.DATESPORT_STATUS_CANCEL) {
                    return APIResponse.returnFail("该约运动已取消，不能申请加入。");
                }
                if (joinedCount >= maxCnt) {
                    tbDatesportJoinInfo.setStatus((byte) 4);
                    bizDatesportJoinInfoDao.saveOrUpdateDatesportJoinInfo(tbDatesportJoinInfo);
                    return APIResponse.returnFail(331, "活动人数已满。");
                }
                if (DatesportConstants.NEED_CHECK == isCheck) {
                    // 发送申请通知到创建者
                    messagePushService.pushApplyForMessage(title, creatorUid, joinnerNickName, joinnerUid, datesportId, joinnerIcon);
                } else if (DatesportConstants.NO_NEED_CHECK == isCheck) {
                    tbDatesportJoinInfo.setStatus((byte) 7);
                    // 增加群组成员
                    IMResponseGroupVo vo = iMService.addMembers(groupId, joinnerUid, creatorUid);
                    if (vo.getErrcode() == null || vo.getErrcode() != 200) {
                        return APIResponse.returnFail("调用c++增加群组接口出错信息如下：" + vo.getErrmsg());
                    }
                    // 设置成员个数、成员图像列表
                    processMemberInfo(tbDatesportInfo, joinUserInfo);
                    // 参与人性别结构
                    Byte gender = bizDatesportJoinInfoDao.getMaxJoinedPeopleGender(datesportId, tbDatesportJoinInfo.getGender(), true);
                    tbDatesportInfo.setGenderStructure(gender);

                    tbDatesportInfoMapper.updateByPrimaryKeySelective(tbDatesportInfo);

                    messagePushService.pushUserAgreeMessage(title, creatorUid, joinnerNickName, joinnerUid, false, joinnerIcon);
                } else {
                    return APIResponse.returnFail("未知isCheck状态");
                }
                break;
            case 2: // 被邀请
                return APIResponse.returnFail("请调用邀请用户接口。");
            case 7:// 已同意邀请加入
            case 3: // 申请加入通过
                if (originalStatus != null && (originalStatus == 3 || originalStatus == 7)) {
                    return APIResponse.returnSuccess("你已加入，无需重复加入。");
                }
                if (datesportStatus != null && datesportStatus == DatesportConstants.DATESPORT_STATUS_CANCEL) {
                    tbDatesportJoinInfo.setStatus((byte) 4);
                    bizDatesportJoinInfoDao.saveOrUpdateDatesportJoinInfo(tbDatesportJoinInfo);
                    return APIResponse.returnSuccess("该活动已取消。");
                }
                if (joinedCount >= maxCnt) {
                    tbDatesportJoinInfo.setStatus((byte) 4);
                    bizDatesportJoinInfoDao.saveOrUpdateDatesportJoinInfo(tbDatesportJoinInfo);
                    return APIResponse.returnFail(331, "活动人数已满。");
                }
                // 增加群组成员
                IMResponseGroupVo vo = iMService.addMembers(groupId, joinnerUid, creatorUid);
                if (vo.getErrcode() == null || vo.getErrcode() != 200) {
                    return APIResponse.returnFail("调用c++增加群组接口出错信息如下：" + vo.getErrmsg());
                }
                if (status == 3) {
                    String headUrl = DatesportHelper.getCreatorHeadUrlByMebersInfoStr(membersInfo);
                    messagePushService.pushCreatorAgreeMessage(title, joinnerUid, datesportId, groupId, headUrl);
                } else if (status == 7) {
                    messagePushService.pushUserAgreeMessage(title, creatorUid, joinnerNickName, joinnerUid, true, joinnerIcon);
                }

                // 设置成员个数、成员图像列表
                processMemberInfo(tbDatesportInfo, joinUserInfo);
                // 参与人性别结构
                Byte gender = bizDatesportJoinInfoDao.getMaxJoinedPeopleGender(datesportId, tbDatesportJoinInfo.getGender(), true);
                tbDatesportInfo.setGenderStructure(gender);
                tbDatesportInfoMapper.updateByPrimaryKeySelective(tbDatesportInfo);
                break;
            case 4: // 被拒绝加入
                messagePushService.pushCreatorRefuseMessage(title, joinnerUid, datesportId, creatorUrl);
                break;
            case 5: // 主动拒绝加入
                messagePushService.pushUserRefuseMessage(title, creatorUid, joinnerNickName, joinnerUid, creatorUrl);
                break;
            case 6: // 创建者
                return APIResponse.returnFail("创建者无需更改状态。");
            case 8: // 已退出
                if (datesportStatus == DatesportConstants.DATESPORT_STATUS_CANCEL) {
                    return APIResponse.returnSuccess("该约运动已经取消了。");
                }
                if (originalStatus == null) {
                    return APIResponse.returnFail("你还没有加入该约运动。");
                }
                if (originalStatus == 6) {
                    return APIResponse.returnFail("创建者不能退出，要退出请调用取消约运动接口。");
                }
                if (originalStatus == 8) {
                    return APIResponse.returnSuccess("你已经退出来该约运动，无需重复退出。");
                }
                if (originalStatus == 3 || originalStatus == 7) {
                    tbDatesportJoinInfo.setStatus((byte) 8);

                    // 删除群成员
                    IMResponseGroupVo responseGroupVo = iMService.deleteMembers(creatorUid, groupId, joinnerUid, datesportId);
                    if (responseGroupVo.getErrcode() != 200) {
                        logger.error("删除群成员出错。晌应{}。", GsonUtils.toJson(responseGroupVo));
                        return APIResponse.returnFail("删除群成员出错。");
                    }
                    // 推送消息告知创建者
                    messagePushService.pushUserExitMessage(title, creatorUid, joinnerUid, joinnerNickName, datesportId, joinnerIcon);

                    // 更新个数
                    tbDatesportInfo.setJoinedCount(tbDatesportInfo.getJoinedCount()-1);
                    // 更新成员头像
                    List<MemberInfo> memberInfoList = DatesportHelper.getMemberListByMebersInfoStr(membersInfo);
                    for (Iterator<MemberInfo> iterator = memberInfoList.iterator(); iterator.hasNext(); ) {
                        if (iterator.hasNext() && iterator.next().getUid().equals(joinnerUid)) {
                            iterator.remove();
                        }
                    }
                    tbDatesportInfo.setMembersInfo(GsonUtils.toJson(memberInfoList));
                    // 参与人性别结构
                    Byte newGender = bizDatesportJoinInfoDao.getMaxJoinedPeopleGender(datesportId, tbDatesportJoinInfo.getGender(), false);
                    tbDatesportInfo.setGenderStructure(newGender);
                    tbDatesportInfoMapper.updateByPrimaryKeySelective(tbDatesportInfo);
                } else {
                    return APIResponse.returnFail("你还没有加入该约运动。");
                }
                break;
            default:
                return APIResponse.returnFail("未知status");
        }

        bizDatesportJoinInfoDao.saveOrUpdateDatesportJoinInfo(tbDatesportJoinInfo);
        return APIResponse.returnSuccess();
    }

    private void processMemberInfo(TbDatesportInfo tbDatesportInfo, RespUserInfoBase joinUserInfo) {
        String membersInfo = tbDatesportInfo.getMembersInfo();

        List<MemberInfo> memberInfoList = DatesportHelper.getMemberListByMebersInfoStr(membersInfo);
        if (memberInfoList.size() < 10) { // 最多加10个
            MemberInfo memberInfo = new MemberInfo();
            memberInfo.setUid(joinUserInfo.getUid());
            memberInfo.setIcon(joinUserInfo.getIcon());
            memberInfo.setNickName(joinUserInfo.getNickName());
            memberInfoList.add(memberInfo);

            tbDatesportInfo.setMembersInfo(GsonUtils.toJson(memberInfoList));
        }

        tbDatesportInfo.setJoinedCount(tbDatesportInfo.getJoinedCount()+1);
    }

    @Override
    public APIResponse<List<RespQueryDatesportItem>> queryDatesport(ReqQueryDatesport reqQueryDatesport, Integer uid) {
        Integer pageNum = reqQueryDatesport.getPageNum();
        Integer pageSize = reqQueryDatesport.getPageSize();
        Byte isCheck = reqQueryDatesport.getIsCheck();
        List<Byte> sportTypes = reqQueryDatesport.getSportTypes();
        Byte genderType = reqQueryDatesport.getGenderType();
        Byte timeFrame = reqQueryDatesport.getTimeFrame();

        TbDatesportInfoExample example = new TbDatesportInfoExample();
        TbDatesportInfoExample.Criteria criteria = example.createCriteria();
        criteria.andCityIdEqualTo(reqQueryDatesport.getCityId());
        if (sportTypes != null && sportTypes.size() >= 1) {
            criteria.andSportTypeIn(sportTypes);
        }
        if (isCheck != null) {
            if (isCheck == 1 || isCheck == 2) {
                criteria.andIsCheckEqualTo(isCheck);
            }
        }
        if (genderType != null) {
            if (genderType == 0) { // 男生多
                genderType = 1;
            } else { // 1 女生多
                genderType = 2;
            }
            List<Byte> genderList = new ArrayList<>();
            genderList.add((byte) 0);// 男女一样多
            genderList.add(genderType);
            criteria.andGenderStructureIn(genderList);
        }
        criteria.andStartTimeGreaterThan(new Date());
        if (timeFrame != null) {
            String currentDateStr = TimeUtils.getSimpleDateEngString(new Date());// 2016-07-15
            Date d = TimeUtils.engStringToDate(currentDateStr + " 23:59:59", TimeUtils.DF_PATTERN_YYYY_MM_DD_HH_MM_SS);;
            switch (timeFrame) {
                case 1://今天
                    criteria.andStartTimeLessThan(d);
                    break;
                case 2://未来三天
                    d = TimeUtils.getDateAfterDate(d, 3);
                    criteria.andStartTimeLessThan(d);
                    break;
                case 3://未来七天
                    d = TimeUtils.getDateAfterDate(d, 7);
                    criteria.andStartTimeLessThan(d);
                    break;
                default:
                    break;
            }
        }
        criteria.andGroupIdIsNotNull();
        criteria.andStatusEqualTo(DatesportConstants.DATESPORT_STATUS_NO_CANCEL);
        example.setPage(new Page(pageNum*pageSize, pageSize));
        example.setOrderByClause("start_time asc");

        List<TbDatesportInfo> list = tbDatesportInfoMapper.selectByExample(example);
        List<RespQueryDatesportItem> respQueryDatesportList = transToRespQueryDatesport(list, uid);
        return APIResponse.returnSuccess(respQueryDatesportList);
    }

    @Override
    public APIResponse<List<RespQueryDatesportItem>> queryMyDatesport(int uid, int pageNum, int pageSize) {
        List<TbDatesportInfo> list = datesportMapper.queryMyDatesport(uid, pageNum*pageSize, pageSize);

        List<RespQueryDatesportItem> respQueryDatesportList = transToRespQueryDatesport(list, uid);
        return APIResponse.returnSuccess(respQueryDatesportList);
    }

    @Override
    public APIResponse<PageObj<List<RespJoinedInfo>>> getJoinedList(int datesportId, int pageNum, int pageSize) {
        List<TbDatesportJoinInfo> joinInfoList = bizDatesportJoinInfoDao.findJoinedByDatesportId(datesportId, pageNum, pageSize);
        List<RespJoinedInfo> joinedInfoList = transToRespJoinedInfo(joinInfoList);
        int totalCnt = datesportMapper.getJoinedCountByDatesportId(datesportId);

        // 刷新成员信息
        if (pageNum == 0) {
            final int idCopy = datesportId;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    refreshMembersInfo(idCopy);
                }
            }).start();
        }

        PageObj<List<RespJoinedInfo>> pageObj = PageObj.create(totalCnt, pageNum, pageSize, joinedInfoList);
        return APIResponse.returnSuccess(pageObj);
    }

    @Override
    public void refreshMembersInfo(int datesportId) {
        TbDatesportInfo tbDatesportInfo = tbDatesportInfoMapper.selectByPrimaryKey(datesportId);
        if (tbDatesportInfo == null) {
            return;
        }
        String membersInfo = tbDatesportInfo.getMembersInfo();
        List<MemberInfo> memberInfoList = DatesportHelper.getMemberListByMebersInfoStr(membersInfo);
        List<Integer> uidList = new ArrayList<>();
        for (MemberInfo memberInfo : memberInfoList ) {
            uidList.add(memberInfo.getUid());
        }
        Map<Integer,RespUserInfoBase> userInfoBaseMap = userServiceFacade.batchQueryUserInfoToMap(uidList);
        if (userInfoBaseMap == null) {
            return;
        }
        boolean hasChange = false;
        for (MemberInfo memberInfo : memberInfoList ) {
            if (!userInfoBaseMap.containsKey(memberInfo.getUid())) {
                continue;
            }
            String oldIcon = memberInfo.getIcon()+"";
            String oldName = memberInfo.getNickName()+"";
            String newIcon = userInfoBaseMap.get(memberInfo.getUid()).getIcon();
            String newName = userInfoBaseMap.get(memberInfo.getUid()).getNickName();
            if (!oldIcon.equals(newIcon) || !oldName.equals(newName)) {
                hasChange = true;
                memberInfo.setIcon(newIcon);
                memberInfo.setNickName(newName);
            }
        }

        if (hasChange) {
            tbDatesportInfo.setMembersInfo(GsonUtils.toJson(memberInfoList));
            tbDatesportInfoMapper.updateByPrimaryKeySelective(tbDatesportInfo);
        }
    }

    @Override
    public APIResponse<?> cancelDatesport(int datesportId, int uid) {
        TbDatesportInfo tbDatesportInfo = tbDatesportInfoMapper.selectByPrimaryKey(datesportId);
        if (tbDatesportInfo == null) {
            return APIResponse.returnFail("datesportId不存在");
        }
        if (uid != tbDatesportInfo.getUid()) {
            return APIResponse.returnFail("你不是该约运动创建者，只要创建者才能取消。");
        }

        List<TbDatesportJoinInfo> joinInfoList = bizDatesportJoinInfoDao.findJoinedByDatesportId(datesportId);
        List<Integer> uidList = new ArrayList<>();
        for (TbDatesportJoinInfo joinInfo : joinInfoList ) {
            if (uid == joinInfo.getUid()) {
                continue;
            }
            uidList.add(joinInfo.getUid());
        }

        // 更新为取消状态
        tbDatesportInfo.setStatus(DatesportConstants.DATESPORT_STATUS_CANCEL);
        tbDatesportInfoMapper.updateByPrimaryKeySelective(tbDatesportInfo);

        // 推送消息告知参与者
        String imgUrl = DatesportHelper.getCreatorHeadUrlByMebersInfoStr(tbDatesportInfo.getMembersInfo());
        if (uidList.size() > 0) {
            messagePushService.pushCancelMessage(tbDatesportInfo.getTitle(), uidList, datesportId, imgUrl);
        }

        // 取消群组
        iMService.quitGroup(uid, tbDatesportInfo.getGroupId(), datesportId);
        return APIResponse.returnSuccess();
    }

    private List<RespJoinedInfo> transToRespJoinedInfo(List<TbDatesportJoinInfo> joinInfoList) {
        List<RespJoinedInfo> respJoinedInfoList = new ArrayList<>();
        List<Integer> uidList = new ArrayList<>();
        for (TbDatesportJoinInfo joinInfo : joinInfoList ) {
            uidList.add(joinInfo.getUid());
        }
        Map<Integer,RespUserInfoBase> userInfoBaseMap = userServiceFacade.batchQueryUserInfoToMap(uidList);
        Map<Integer,List<RespOpenUserInterest>> interestMap = userServiceFacade.batchQueryUserInterest(uidList);
        for (TbDatesportJoinInfo joinInfo : joinInfoList ) {
            RespJoinedInfo respJoinedInfo = new RespJoinedInfo();
            respJoinedInfo.setUid(joinInfo.getUid());
            respJoinedInfo.setDatesportId(joinInfo.getDatesportId());

            if (userInfoBaseMap != null && userInfoBaseMap.containsKey(joinInfo.getUid())) {
                RespUserInfoBase userInfo = userInfoBaseMap.get(joinInfo.getUid());
                respJoinedInfo.setNickName(userInfo.getNickName());
                respJoinedInfo.setIcon(userInfo.getIcon());
                respJoinedInfo.setGender(userInfo.getGender());
                respJoinedInfo.setLevel(userInfo.getLevel());
            }
            List<String> tagsList = new ArrayList<>();
            if (interestMap != null && interestMap.containsKey(joinInfo.getUid())) {
                List<RespOpenUserInterest> interestList = interestMap.get(joinInfo.getUid());
                for (RespOpenUserInterest interest : interestList) {
                    tagsList.add(interest.getName());
                }
            }
            // 兴趣列表
            respJoinedInfo.setTagsList(tagsList);
            respJoinedInfoList.add(respJoinedInfo);
        }
        return respJoinedInfoList;
    }

    private List<RespQueryDatesportItem> transToRespQueryDatesport(List<TbDatesportInfo> tbDatesportInfoList, Integer uid) {
        // 批量从数据库里查找出来，获取参加状态
        List<Integer> datesportIdList = new ArrayList<>();
        for (TbDatesportInfo info : tbDatesportInfoList) {
            datesportIdList.add(info.getId());
        }

        List<TbDatesportJoinInfo> joinInfoList = new ArrayList<>();
        if (datesportIdList.size() >0 && uid != null) {
            joinInfoList = bizDatesportJoinInfoDao.findByDatesportIdAndUid(datesportIdList, uid);
        }
        Map<Integer, TbDatesportJoinInfo> joinInfoMap = new HashMap<>();// key - datesportId  value - TbDatesportJoinInfo
        for (TbDatesportJoinInfo joinInfo : joinInfoList) {
            joinInfoMap.put(joinInfo.getDatesportId(), joinInfo);
        }

        List<RespQueryDatesportItem> list = new ArrayList<RespQueryDatesportItem>();
        for (TbDatesportInfo info : tbDatesportInfoList) {
            RespQueryDatesportItem item = new RespQueryDatesportItem();
            Integer creatorUid = info.getUid();

            item.setAddress(info.getAddress());
            item.setStartTime(info.getStartTime());
            item.setPlayerCount(info.getPlayerCount());
            item.setDatesportId(info.getId());
            item.setTagList(DatesportHelper.getTagListByTbDatesportInfo(info));
            item.setTitle(info.getTitle());
            item.setIsCheck(info.getIsCheck());
            item.setCreatorUid(creatorUid);
            item.setMembersCount(info.getJoinedCount());
            item.setDatesportStatus(info.getStatus());
            item.setPayType(info.getPayType());

            // 成员图象
            List<MemberInfo> memberInfoList = DatesportHelper.getMemberListByMebersInfoStr(info.getMembersInfo());
            List<String> members = new ArrayList<>();
            for (int i=0; i<memberInfoList.size(); i++) {
                MemberInfo memberInfo = memberInfoList.get(i);
                if (i == 0) { //第一个为创建者
                    item.setCreatorIcon(memberInfo.getIcon());
                    item.setNickname(memberInfo.getNickName());
                }
                members.add(memberInfo.getIcon());
            }
            item.setMembers(members);

            // 参加状态
            if (joinInfoMap.containsKey(info.getId())) {
                Byte joinStatus = joinInfoMap.get(info.getId()).getStatus();
                item.setJoinStatus(joinStatus);
            } else {
                item.setJoinStatus((byte) 0);
            }

            list.add(item);
        }
        return list;
    }

    private List<RespNoticeInfo> transToRespNoticeInfo(List<TbDatesportNoticeInfo> noticeInfoList) {
        List<RespNoticeInfo> list = new ArrayList<RespNoticeInfo>();
        for (TbDatesportNoticeInfo info : noticeInfoList) {
            RespNoticeInfo respInfo = new RespNoticeInfo();
            respInfo.setCreateTime(info.getCreateTime());
            respInfo.setNotice(info.getNotice());
            list.add(respInfo);
        }
        return list;
    }
}
